package com.github.elliot.gatewaycenter.util;

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.GCMParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.Base64;

/**
 * 对称加密
 */
public class AESEncryptionUtil {

    private static final String ALGORITHM = "AES";
    private static final String TRANSFORMATION = "AES/GCM/NoPadding";
    private static final int AES_KEY_SIZE = 256;
    private static final int GCM_TAG_LENGTH = 128; // bits
    private static final int GCM_IV_LENGTH = 12;   // bytes (推荐值)

    /**
     * 生成 AES 密钥
     */
    public static SecretKey generateKey() throws NoSuchAlgorithmException {
        KeyGenerator keyGenerator = KeyGenerator.getInstance(ALGORITHM);
        keyGenerator.init(AES_KEY_SIZE);
        return keyGenerator.generateKey();
    }

    /**
     * 从 Base64 字符串加载密钥
     */
    public static SecretKey loadKey(String base64Key) {
        byte[] decodedKey = Base64.getDecoder().decode(base64Key);
        return new SecretKeySpec(decodedKey, ALGORITHM);
    }

    /**
     * 导出密钥为 Base64 字符串
     */
    public static String exportKey(SecretKey secretKey) {
        return Base64.getEncoder().encodeToString(secretKey.getEncoded());
    }

    /**
     * AES-GCM 加密（推荐）
     */
    public static String encrypt(String plaintext, SecretKey secretKey) throws Exception {
        // 生成随机 IV
        byte[] iv = new byte[GCM_IV_LENGTH];
        SecureRandom secureRandom = new SecureRandom();
        secureRandom.nextBytes(iv);

        // 初始化 cipher
        Cipher cipher = Cipher.getInstance(TRANSFORMATION);
        GCMParameterSpec parameterSpec = new GCMParameterSpec(GCM_TAG_LENGTH, iv);
        cipher.init(Cipher.ENCRYPT_MODE, secretKey, parameterSpec);

        // 加密
        byte[] ciphertext = cipher.doFinal(plaintext.getBytes(StandardCharsets.UTF_8));

        // 组合 IV + 密文
        byte[] encryptedData = new byte[iv.length + ciphertext.length];
        System.arraycopy(iv, 0, encryptedData, 0, iv.length);
        System.arraycopy(ciphertext, 0, encryptedData, iv.length, ciphertext.length);

        return Base64.getEncoder().encodeToString(encryptedData);
    }

    /**
     * AES-GCM 解密
     */
    public static String decrypt(String encryptedData, SecretKey secretKey) throws Exception {
        byte[] decodedData = Base64.getDecoder().decode(encryptedData);

        // 提取 IV
        byte[] iv = new byte[GCM_IV_LENGTH];
        System.arraycopy(decodedData, 0, iv, 0, iv.length);

        // 提取密文
        byte[] ciphertext = new byte[decodedData.length - GCM_IV_LENGTH];
        System.arraycopy(decodedData, iv.length, ciphertext, 0, ciphertext.length);

        // 初始化 cipher
        Cipher cipher = Cipher.getInstance(TRANSFORMATION);
        GCMParameterSpec parameterSpec = new GCMParameterSpec(GCM_TAG_LENGTH, iv);
        cipher.init(Cipher.DECRYPT_MODE, secretKey, parameterSpec);

        // 解密
        byte[] plaintext = cipher.doFinal(ciphertext);
        return new String(plaintext, StandardCharsets.UTF_8);
    }

    /**
     * 使用密码派生密钥的加密（Password-Based Encryption）
     */
    public static String encryptWithPassword(String plaintext, String password) throws Exception {
        // 使用 PBKDF2 派生密钥
        SecretKey secretKey = deriveKeyFromPassword(password);
        return encrypt(plaintext, secretKey);
    }

    public static String decryptWithPassword(String encryptedData, String password) throws Exception {
        SecretKey secretKey = deriveKeyFromPassword(password);
        return decrypt(encryptedData, secretKey);
    }

    private static SecretKey deriveKeyFromPassword(String password) throws Exception {
        // 在实际应用中应该使用安全的盐值和迭代次数
        // 这里简化实现，实际项目应该从安全配置读取
        byte[] salt = "固定盐值-应该随机生成".getBytes(); // 实际应该随机生成并存储
        int iterations = 10000;

        javax.crypto.spec.PBEKeySpec spec = new javax.crypto.spec.PBEKeySpec(
                password.toCharArray(), salt, iterations, AES_KEY_SIZE
        );
        javax.crypto.SecretKeyFactory factory = javax.crypto.SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256");
        byte[] keyBytes = factory.generateSecret(spec).getEncoded();
        return new SecretKeySpec(keyBytes, ALGORITHM);
    }

    public static void main(String[] args) throws Exception {
        String base64Key = "XYyOyWILUQ9IYXbeTv8u/3t7nGXCAfyzD2/ESrEtR5o=";
        String encryptedData = "79RdwAPosH/9ZLlWaWFrS95tg0rTjCzrZNVdL2HLMRE=";
        SecretKey secretKey = AESEncryptionUtil.loadKey(base64Key);
        String decrypt = AESEncryptionUtil.decrypt(encryptedData, secretKey);
        System.out.println("解密后的数据:" + decrypt);
    }

    private static void example(){
        try {
            // 生成密钥
            SecretKey secretKey = AESEncryptionUtil.generateKey();
            String base64Key = AESEncryptionUtil.exportKey(secretKey);
            System.out.println("生成的密钥: " + base64Key);

            // 加密
            String plaintext = "这是敏感数据";
            String encrypted = AESEncryptionUtil.encrypt(plaintext, secretKey);
            System.out.println("加密结果: " + encrypted);

            // 解密
            String decrypted = AESEncryptionUtil.decrypt(encrypted, secretKey);
            System.out.println("解密结果: " + decrypted);

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
